关于这道题,我实在想不通为何被列入了 Medium 的行列,插入排序是知乎上有名的梗,如果这个算法不能在十分钟内流畅的写出来,应该万般羞愧的躲进活死人墓,苦练各种基本功。


简单过一下插入排序的过程吧:

[3 7] 4 9 5 2 6 1
^   ^
[3 4 7 9] 5 2 6 1
^     ^
[3 4 5 7 9] 2 6 1
^           ^
[2 3 4 5 7 9] 6 1
^     ^
[2 3 4 5 6 7 9] 1
^               ^
[1 2 3 4 5 6 7 9]

从上述过程中,可以看出,每一次遇到逆序情况(即 7->4, 9->5, 9->2, 9->6, 9->1 等情况)时,都需要从头开始比对,遇到合适的位置,便将当前元素插过去。所以算法的核心是:

1->3->4->2->5 => 1->2->3->4->5
 ^    ^
i  p pNode

的过程如何实现。假设当前指针为 p,要插入的节点指针 pNode,从头检测的指针为 i, 则有:

ListNode *pNode = p->next;
p->next = pNode->next;
pNode->next = i->next;
i->next = pNode;

如果看不太明白,还需要动手在纸上画一画,链表题如果不动手,的确是很难理清楚的。

#include <cstddef>

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode *insertionSortList(ListNode *head) {
        ListNode pre_head(0);
        pre_head.next = head;
        for (ListNode *p = head; p; )
            if (p->next && p->val > p->next->val) {
                ListNode *i = &pre_head;
                while (!(i->next->val > p->next->val))
                    i = i->next;
                ListNode *pNode = p->next;
                p->next = pNode->next;
                pNode->next = i->next;
                i->next = pNode;
            } else { p = p->next; }
        return pre_head.next;
    }
};

LeetCode Direct Link